//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using System.Xml.Serialization;
using OpenLS.Core.Serialization;

namespace OpenLS.Drawing.Diagram
{
    sealed class IteratorAttributes
    {
        private AxisType _axis;
        private ElementType _ptType = ElementType.All;
        private bool _hideLastTrans;
        private readonly List<int> _st = new List<int>(new[]{1});
        private readonly List<int> _cnt = new List<int>(new[]{0});
        private readonly List<int> _step = new List<int>(new[] { 1 });
        [ThreadStatic]
        static readonly AxisTypeLookup AxisTypeConverter = new AxisTypeLookup();
        [ThreadStatic]
        static readonly ElementTypeLookup ElementTypeConverter = new ElementTypeLookup();

        private sealed class ElementTypeLookup: EnumLookup<ElementType>
        {
            protected override ElementType CombineValues(ElementType result, ElementType dictionary)
            {
                return result | dictionary;
            }
        }

        sealed class AxisTypeLookup : EnumLookup<AxisType>
        {
            protected override AxisType CombineValues(AxisType result, AxisType dictionary)
            {
                return result
                       | dictionary;
            }
        }
        private abstract class EnumLookup<T>
        {
            private Dictionary<string, T> _map;

            private Dictionary<string, T> Map
            {
                get
                {
                    var m = new Dictionary<string, T>();
                    foreach (FieldInfo f in (typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static)))
                    {
                        string name = f.Name;
                        foreach (XmlEnumAttribute a in f.GetCustomAttributes(typeof(XmlEnumAttribute), false))
                            name = a.Name;
                        m[name] = (T)f.GetValue(null);
                    }
                    _map = m;
                    return _map;
                }
            }

            public T GetValue (string s, T defaultValue)
            {
                if (s == null)
                    return defaultValue;
                T result = default(T);
               // new EnumConverter(typeof (T));

                foreach (string s2  in s.Split(' '))
                {
                    string s3 = s2.Trim();
                    result = CombineValues(result, Map[s3]);
                }
                return result;
            }

            protected abstract T CombineValues(T result, T dictionary);
            
            public string StringValue (T t, string defaultValue)
            {
                var result = new StringBuilder();
                bool had = false;
                var tString = t.ToString();
                Debug.WriteLine(tString);
                var ts = new List<string>(tString.Split(','));
                var tts = new Dictionary<string, string>();
                foreach (string s in ts)
                {
                    tts.Add(s.Trim(), s.Trim());
                }
                
                foreach (KeyValuePair<string, T> map in Map)
                {

                    if (tString != default(T).ToString())
                        if (tts.ContainsKey(map.Value.ToString()))
                        {
                            if (had)
                                result.Append(" " + map.Key);
                            else
                            {
                                result.Append(map.Key);
                                had = true;
                            }
                        }
                }
                if (!had)
                    return defaultValue;
                return result.ToString();
            }
        }


        internal void ReadXml (ReadContext c)
        {
            _axis = AxisTypeConverter.GetValue(c.GetOptionalString("axis"), AxisType.None);
            //_axis = c.GetOptionalEnum<AxisType>("axis", AxisType.None); //\\list?
            _ptType = ElementTypeConverter.GetValue(c.GetOptionalString("ptType"), ElementType.All);//\\ c.GetOptionalEnum<ElementType>("ptType", ElementType.All);//\\list?
            _hideLastTrans = c.GetOptionalBoolean("hideLastTrans", true);
            _st.Clear();
            _st.AddRange(parseIntegers (c.GetOptionalString("st"), 1));//\\list?
            _cnt.Clear();
            _cnt.AddRange(parseUIntegers (c.GetOptionalString("cnt"), 0)); //\\ type?
            _step.Clear();
            _step.AddRange(parseIntegers(c.GetOptionalString("step"), 1));//\\list?
        }

        private static IEnumerable<int> parseIntegers(string s, int defaultValue)
        {
            if (s == null)
            {
                yield return defaultValue;
                yield break;
            }
            foreach (string split in s.Split(' '))
            {
                yield return
                int.Parse(split.Trim());
            }

        }
        private static IEnumerable<int> parseUIntegers(string s, int defaultValue)
        {
            if (s == null)
            {
                yield return defaultValue;
                yield break;
            }
            foreach (string split in s.Split(' '))
            {
                yield return
                (int) uint.Parse(split.Trim());
            }

        }

        public void WriteXml(WriteContext c)
        {
            if (_axis != AxisType.None)
                c.SetString("axis", AxisTypeConverter.StringValue(_axis, "none"));
            if (_ptType != ElementType.All)
                c.SetString("ptType", ElementTypeConverter.StringValue(_ptType, "all"));

            c.SetOptionalBoolean("hideLastTrans", _hideLastTrans, true);
            c.SetOptionalString("st", concat(_st), "1");//\\list?
            c.SetOptionalString("cnt", concat(_cnt), "0"); //\\ type?
            c.SetOptionalString("step", concat(_step), "1");//\\list?
        }
        static string concat<T> (IEnumerable<T> items)
        {
            var  result = new StringBuilder();
            bool  first = true;
            foreach (T item in items)
            {
                if (!first)
                    result.Append(" ");
                result.Append(item);
                first = false;
            }
            return result.ToString();
        }
    }
}

